package com.edu.lxshpc.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.edu.lxshpc.dto.UserDto;
import com.edu.lxshpc.pojo.*;
import com.edu.lxshpc.mapper.UserMapper;
import com.edu.lxshpc.povo.UserVO;
import com.edu.lxshpc.service.*;
import com.edu.lxshpc.utils.MyException;
import com.edu.lxshpc.utils.Result;
import com.edu.lxshpc.utils.Utils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.edu.lxshpc.utils.RedisStatic.*;

/**
 * @author Sanshan
 * @description 针对表【user】的数据库操作Service实现
 * @createDate 2023-10-27 09:57:01
 */
@Service
@Slf4j
@Transactional
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements UserService {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private SysRoleService roleService;

    @Autowired
    private SysUserRoleService sysUserRoleService;

    @Autowired
    private SysRolePermissionService rolePermissionService;
    @Autowired
    private SysPermissionService permissionService;
    /**
     * 用户注册，
     *
     * @param user 用户信息
     * @param code 验证码
     * @return 通用结果集
     */
    @Override
    public Result insertUser(User user, String code) {
        QueryWrapper<User> query = new QueryWrapper<>();
        query.eq("username", user.getUsername());
        boolean exists = userMapper.exists(query);
        if (exists) {
            return Result.fail("用户已存在");
        }
        String rCode = stringRedisTemplate.opsForValue().get(USER_REGISTER_CODE + user.getUsername());
        if (rCode == null || "".equals(rCode)) {
            return Result.fail("验证码不存在");
        }
        if (rCode.equals(code)) {
            user.setId(IdUtil.getSnowflake().nextId());
            user.setNickname("lxsh_user" + RandomUtil.randomString(8));
            user.setAvatar("https://telegraph-image-eul.pages.dev/file/144934039e57e6cf2092b.jpg");
            userMapper.insert(user);
            insertRole(user);
            return Result.success(user);
        }

        return Result.fail("验证码错误");
    }

    private void insertRole(User user) {
        SysUserRole sysUserRole = new SysUserRole();
        sysUserRole.setUserId(user.getId());
        sysUserRole.setRoleId(1);
        sysUserRoleService.save(sysUserRole);
    }


    /**
     * 用户登录
     *
     * @param user 用户名
     * @return 通用响应业务结果
     */
    @Override
    public Result userLoginByUsername(User user) {
//        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUsername(),user.getPassword()
//        );
//        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        // 先查询缓存，若存在
        String userJson = stringRedisTemplate.opsForValue().get(USER_LOGIN_KEY + user.getUsername());
        // 为空，则查询数据库
        if (userJson == null) {
            //构造查询条件
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.select("id","nickname","username","status","avatar");
            queryWrapper.eq("username", user.getUsername());
            //查询后的结果赋值给user
            user = userMapper.selectOne(queryWrapper);
            //查询权限
            ArrayList<GrantedAuthority> list = getGrantedAuthorities(user);
            String auth = list.stream().map(item -> item.getAuthority()).collect(Collectors.joining(","));
            //设置权限
            user.setAuthority(auth);
            //设置token
            user.setToken(Utils.createToken(user));
            UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
            // redis做缓存
            String userJSON = JSONUtil.toJsonStr(userVO);
            stringRedisTemplate.opsForValue().set(USER_LOGIN_KEY + user.getUsername(), userJSON,14,TimeUnit.DAYS);
            return Result.success(userVO);
        }
        UserVO userVO = JSONUtil.toBean(userJson, UserVO.class);
        if(userVO.getStatus() == 2){
            return Result.fail("用户已被禁用,请联系管理员");
        }
        return Result.success(userVO);
    }

    /**
     * 查询用户信息
     *
     * @param username 用户名
     * @return 返回查到的user信息
     */
    @Override
    public User queryByUsername(String username) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", username);
        return userMapper.selectOne(queryWrapper);
    }

    /**
     * 根据用户id查需用户角色
     * @param id 用户id
     * @return
     */
    @Override
    public List<SysRole> getUserRoleById(Long id) {
        // 获取用户信息
        QueryWrapper<User> query = new QueryWrapper<>();
        query.select("id","username","nickname","status","avatar");
        query.eq("id", id);
        User user = userMapper.selectOne(query);
        // 为空抛出异常
        if (user == null) {
            throw new MyException("用户不存在");
        }
        // 查询用户角色Id集合
        QueryWrapper<SysUserRole> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", user.getId());
        // 根据角色id集合查询对应角色信息
        List<SysUserRole> list = sysUserRoleService.list(queryWrapper);
        List<Integer> roleList = list.stream().map(item -> item.getRoleId()).collect(Collectors.toList());
        List<SysRole> sysRolesList = roleService.listByIds(roleList);
        return sysRolesList;
    }

    /**
     * 根据用id查询角色权限
     * @param sysRoles 用户角色信息
     * @return
     */
    @Override
    public List<SysPermission> getUserPermissionsByRoleId(List<SysRole> sysRoles) {
        if (sysRoles == null) {
            throw new MyException("用户不存在");
        }
        //开启setrem流获得角色id
        List<Integer> roleList = sysRoles
                .stream()
                .map(item -> item.getRoleId())
                .collect(Collectors.toList());
        QueryWrapper<SysRolePermission> sysRolePermissionQueryWrapper = new QueryWrapper<>();
        sysRolePermissionQueryWrapper.in("role_id", roleList);
        List<SysRolePermission> rolePermissions = rolePermissionService.list(sysRolePermissionQueryWrapper);
        // 开启stream流获得权限信息
        List<Integer> collect = rolePermissions.stream()
                .map(item -> item.getPermissionId())
                .distinct() // 去重
                .collect(Collectors.toList());
        // 根据权限id获得权限信息
        QueryWrapper<SysPermission> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("parent_id", collect);
        List<SysPermission> list = permissionService.list(queryWrapper);
        return list;
    }

    /**
     *  获得用户权限信息
     * @param user 参数
     * @return
     */
    @Override
    public ArrayList<GrantedAuthority> getGrantedAuthorities(User user) {
        List<SysRole> sysRoles = this.getUserRoleById(user.getId());
        List<SysPermission> sysPermissions = this.getUserPermissionsByRoleId(sysRoles);
        String[] authority = new String[sysRoles.size()+sysPermissions.size()];
        ArrayList<GrantedAuthority> list = new ArrayList<>();
        for (int i = 0; i < sysRoles.size(); i++) {
            authority[i]="ROLE_" + sysRoles.get(i).getRole();
            list.add(new SimpleGrantedAuthority("ROLE_" + sysRoles.get(i).getRole()));
        }
        for (int i = 0; i < sysPermissions.size(); i++) {
            authority[sysRoles.size()+i]=sysPermissions.get(i).getUrl();
        }
        return list;
    }
    /**
     * 根据用户id查询用户信息
     * @param userId 用户id
     * @return 用户信息
     */
    @Override
    public Result getUserById(Long userId) {
        User user = userMapper.selectOne(new QueryWrapper<User>().eq("id", userId));
        UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
        return Result.success(userVO);
    }
    /**
     * 更新用户信息
     * @param userVO 用户信息
     * @return 业务结果
     */
    @Override
    public Result updateUserById(UserVO userVO) {
        if (BeanUtil.isEmpty(userVO)) {
            return Result.fail("用户信息不能为空");
        }
        User user = BeanUtil.copyProperties(userVO, User.class);
        int i = userMapper.updateById(user);
        String userJSON = JSON.toJSONString(user);
        stringRedisTemplate.opsForValue().set(USER_LOGIN_KEY + user.getUsername(), userJSON,14,TimeUnit.DAYS);
        return i>0?Result.success("更新成功！"):Result.fail("更新失败！");
    }
    /**
     * 更新用户密码
     * @param userDto 用户信息
     * @return 返回用户信息
     */
    @Override
    public Result updatePasswordById(UserDto userDto) {
        log.info("updatePasswordById: {}", userDto);
        // userDto 为空返回错误信息
        if (BeanUtil.isEmpty(userDto)) {
            return Result.fail("用户信息不能为空");
        }
        // 两次密码不一致，返回错误信息
        if(!userDto.getNewPass().equals(userDto.getRepass())){
            return Result.fail("两次密码不一致");
        }
        // 查询用户信息
        User user = userMapper.selectOne(new QueryWrapper<User>().eq("id", userDto.getId()));
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        // 旧密码匹配
        boolean matches = encoder.matches(userDto.getPassword(), user.getPassword());
        // 验证旧密码
        if(matches){
            user = BeanUtil.copyProperties(userDto, User.class);
            //加密新密码
            user.setPassword(encoder.encode(userDto.getNewPass()));
            int i = userMapper.updateById(user);
            String userJSON = JSON.toJSONString(user);
            stringRedisTemplate.opsForValue().set(USER_LOGIN_KEY + user.getUsername(), userJSON,14,TimeUnit.DAYS);
            return i>0 ? Result.success("更新成功！") : Result.fail("更新失败！");
        }
        return Result.fail("密码错误");
    }

}



